package zcj.stu.C48;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.EventListener;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.ResolvableType;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Predicate;

@Configuration
@Slf4j
public class C48_1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(C48_1.class);
//        SmsApplicationListener sms = context.getBean(SmsApplicationListener.class);
        MyService myService = context.getBean(MyService.class);
        myService.doBusiness();
        context.close();
    }
    static class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) {
            super(source);
        }
    }
    @Component
    static class MyService{
        @Autowired
        private ApplicationEventPublisher publisher;
        public void doBusiness(){
            System.out.println("主线任务...");
            publisher.publishEvent(new MyEvent("s_doBusiness"));
        }
    }
    @Component
    static class SmsApplicationListener{
        @MyListener
        public void sendMoney(MyEvent event){
            System.out.println(event);
//            System.out.println();
            log.debug("给用户回馈了0.01元...");
        }
        public void charge(){
            System.out.println("充值...");
        }
    }
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    static @interface MyListener{

    }
    @Component
    static class EmailApplicationListener implements ApplicationListener<MyEvent> {
        @Override
        public void onApplicationEvent(MyEvent event) {
            System.out.println(event);
            log.debug("发生了一条邮件...");
        }
        @MyListener
        public void charge(MyEvent event){
            System.out.println("邮箱充值...");
        }
        @MyListener
        public void charge1(MyEvent event){
            System.out.println("邮箱充值1...");
        }
    }
    @Bean
    static SmartInitializingSingleton smartInitializingSingleton(ConfigurableApplicationContext context){
        return () -> {
            for (String beanName : context.getBeanDefinitionNames()) {
                Object bean = context.getBean(beanName);
                for (Method method :bean.getClass().getMethods()) {
                    if (method.isAnnotationPresent(MyListener.class)) {
                        ApplicationListener listener = new ApplicationListener() {
                            @Override
                            public void onApplicationEvent(ApplicationEvent event) {
//                        if(event.getClass()!=method.getParameterTypes()[0])return;
                                if(!method.getParameterTypes()[0].isAssignableFrom(event.getClass()))return;
                                try {
                                    method.invoke(bean,event);
                                } catch (Exception e)  {
                                    e.printStackTrace();
                                }
                            }
                        };
                        context.addApplicationListener(listener);
                    }
                }
            }
        };
    }
    @Bean
    public ThreadPoolTaskExecutor executor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        return executor;
    }
    @Bean
    SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor){
        SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
        multicaster.setTaskExecutor(executor);
        return multicaster;
    }
//    @Component
//    static class Feed{
//        @EventListener
//        public void sendMoney(){
//            System.out.println("给用户回馈了0.01元...");
//        }
//    }
}
